package cn.zhqr.lib.utils;

import com.jfinal.kit.StrKit;
import org.apache.log4j.Logger;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalTime;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by charles on 2018/6/21.
 */
public class DateUtils {
    private static final Logger log = Logger.getLogger(DateUtils.class);

    public static java.sql.Date toSqlDate(Date date){
        return new java.sql.Date(date.getTime());
    }
    public static Long getTodayStartSecond(){
        return getStartSecond(new Date());
    }
    public static Long getTodayEndSecond(){
        return getEndSecond(new Date());
    }
    public static Date yesterday(){
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DAY_OF_YEAR,-1);
        return calendar.getTime();
    }
    public static Date lastMonthFirstDay(){
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MONTH,-1);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        return calendar.getTime();
    }

    public static Date addDays(int days){
        return addDays(new Date(),days);
    }

    public static Date addDays(Date date,int days){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_YEAR, days);
        return calendar.getTime();
    }

    public static Date addHours(int hours){
        return addHours(new Date(),hours);
    }

    public static Date addHours(Date date,int hours){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.HOUR, hours);
        return calendar.getTime();
    }
    public static Date addHours(long timestamp,int hours){
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(timestamp);
        calendar.add(Calendar.HOUR, hours);
        return calendar.getTime();
    }

    public static int getWeek(){
        Calendar today = Calendar.getInstance();
        return today.get(Calendar.WEEK_OF_MONTH);
    }

    /**
     * 获取中国版的星期数，周一到周天分别是0到6
     * @return
     */
    public static int getChinaDayOfWeek(Date date){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int week = calendar.get(Calendar.DAY_OF_WEEK)-2;
        return week==-1?6:week;
    }

    /**
     * 获取中国今天的星期数，周一到周天分别是0到6
     * @return
     */
    public static int getChinaDayOfWeek(){
        return getChinaDayOfWeek(new Date());
    }

    public static Long getStartSecond(Date date){
        return getStartTimeOfDay(date).getTime()/1000;
    }

    public static Date getStartTimeOfDay(Date date){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY,0);
        calendar.set(Calendar.MINUTE,0);
        calendar.set(Calendar.SECOND,0);
        calendar.set(Calendar.MILLISECOND,0);

        return calendar.getTime();
    }


    public static Date getEndTimeOfDay(Date date){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY,23);
        calendar.set(Calendar.MINUTE,59);
        calendar.set(Calendar.SECOND,59);
//        calendar.set(Calendar.MILLISECOND,999);

        return calendar.getTime();
    }

    public static Long getEndSecond(Date date){
        return getEndTimeOfDay(date).getTime()/1000;
    }

    public static Long getStartSecondOfMonth(Date date){
        return getStartOfMonth(date).getTime()/1000;
    }

    public static Long getEndSecondOfMonth(Date date){
        return getEndTimeOfDay(date).getTime()/1000;
    }


    public static Date getStartOfMonth(Date date){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY,0);
        calendar.set(Calendar.MINUTE,0);
        calendar.set(Calendar.SECOND,0);
        calendar.set(Calendar.MILLISECOND,0);

        return calendar.getTime();
    }

    public static Date getEndOfMonth(Date date){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MONTH, 1);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY,0);
        calendar.set(Calendar.MINUTE,0);
        calendar.set(Calendar.SECOND,0);
        calendar.set(Calendar.MILLISECOND,0);

        calendar.add(Calendar.MILLISECOND,-1);

        return calendar.getTime();
    }

    public static Long getStartSecondOfYear(Integer year){
        return getStartTimeOfYear(year).getTime()/1000;
    }
    public static Date getStartTimeOfYear(Integer year){
        Calendar calendar = Calendar.getInstance();

        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, 0);
        calendar.set(Calendar.DAY_OF_MONTH, 1);

        calendar.set(Calendar.HOUR_OF_DAY,0);
        calendar.set(Calendar.MINUTE,0);
        calendar.set(Calendar.SECOND,0);
        calendar.set(Calendar.MILLISECOND,0);

        return calendar.getTime();
    }

    public static Date getEndTimeOfYear(Integer year){
        Calendar calendar = Calendar.getInstance();

        calendar.set(Calendar.YEAR, year+1);
        calendar.set(Calendar.MONTH, 0);
        calendar.set(Calendar.DAY_OF_MONTH, 1);

        calendar.set(Calendar.HOUR_OF_DAY,0);
        calendar.set(Calendar.MINUTE,0);
        calendar.set(Calendar.SECOND,0);
        calendar.set(Calendar.MILLISECOND,0);

        calendar.add(Calendar.MILLISECOND,-1);

        return calendar.getTime();
    }

    public static Long getEndSecondOfYear(Integer year){
        return getEndTimeOfYear(year).getTime()/1000;
    }

    public static Long nowSecond(){
        return System.currentTimeMillis()/1000;
    }

    public static Date getFirstDayOfMonth(Date date){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_MONTH,1);
        return calendar.getTime();
    }

    public static Date getStartTimeOfLastMonth(){
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MONTH,-1);
        calendar.set(Calendar.DAY_OF_MONTH,1);
        calendar.set(Calendar.HOUR_OF_DAY,0);
        calendar.set(Calendar.MINUTE,0);
        calendar.set(Calendar.SECOND,0);
        calendar.set(Calendar.MILLISECOND,0);

        return calendar.getTime();
    }

    public static Date getEndTimeOfLastMonth(){
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.DAY_OF_MONTH,1);
        calendar.set(Calendar.HOUR_OF_DAY,0);
        calendar.set(Calendar.MINUTE,0);
        calendar.set(Calendar.SECOND,0);
        calendar.set(Calendar.MILLISECOND,0);

        calendar.add(Calendar.MILLISECOND, -1);
        return calendar.getTime();
    }

    public static Date getStartTimeOfYearMonth(Integer year,Integer month){
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR,year);
        calendar.set(Calendar.MONTH,month);
        calendar.set(Calendar.DAY_OF_MONTH,1);
        calendar.set(Calendar.HOUR_OF_DAY,0);
        calendar.set(Calendar.MINUTE,0);
        calendar.set(Calendar.SECOND,0);
        calendar.set(Calendar.MILLISECOND,0);

        return calendar.getTime();
    }

    public static Date getEndTimeOfYearMonth(Integer year,Integer month){
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR,year);
        calendar.set(Calendar.MONTH,month);
        calendar.set(Calendar.DAY_OF_MONTH,1);
        calendar.set(Calendar.HOUR_OF_DAY,0);
        calendar.set(Calendar.MINUTE,0);
        calendar.set(Calendar.SECOND,0);
        calendar.set(Calendar.MILLISECOND,0);

        calendar.add(Calendar.MONTH,1);
        calendar.add(Calendar.MILLISECOND,-1);

        return calendar.getTime();
    }

    public static int getDayOfYear(Date time) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);

        return calendar.get(Calendar.DAY_OF_YEAR);
    }

    public static int getDayOfYear() {
        Calendar calendar = Calendar.getInstance();
        return calendar.get(Calendar.DAY_OF_YEAR);
    }

    public static int getYear(Date time) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);
        return calendar.get(Calendar.YEAR);
    }

    public static int getCurYear() {
        Calendar calendar = Calendar.getInstance();
        return calendar.get(Calendar.YEAR);
    }

    public static int getLastYear() {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.YEAR,-1);
        return calendar.get(Calendar.YEAR);
    }

    public static int getMonth(Date time) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);
        return calendar.get(Calendar.MONTH);
    }

    public static int getCurMonth() {
        Calendar calendar = Calendar.getInstance();
        return calendar.get(Calendar.MONTH);
    }

    public static int getLastMonth() {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MONTH,-1);
        return calendar.get(Calendar.MONTH);
    }

    public static int getYearMonth(Date time) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);
        return calendar.get(Calendar.YEAR)*100 + calendar.get(Calendar.MONTH)+1;
    }

    public static int getDayOfYear(Long second) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date(second*1000));

        return calendar.get(Calendar.DAY_OF_YEAR);
    }

    public static String formatTimestamp(int timestamp){
        int hours = timestamp/3600;
        int minutes = timestamp/60 - hours*60 ;
        int seconds = timestamp % 60;

        StringBuilder res = new StringBuilder();
        if(hours>0){
            res.append(hours).append("小时");
        }
        if(minutes>0){
            res.append(minutes).append("分");
        }
        res.append(seconds).append("秒");
        return res.toString();
    }

    public static Date parseDate(String date,String format){
        try{
            return getDateFormat(format).parse(date);
        }catch (Exception e){
            return null;
        }
    }

    public static String formatDate(String format, Date date){
        if(date==null){
            date = new Date();
        }
        return getDateFormat(format).format(date);
    }

    public static String friendlyTime(long duration, boolean show_seconds) {
        long hours = duration/3600;
        long minutes = (duration - hours*3600)/60;
        long seconds = duration % 60;

        StringBuilder sb  = new StringBuilder();
        if(hours > 0) {
            sb.append(hours).append("小时");
        }
        if(minutes > 0) {
            sb.append(minutes).append("分钟");
        }
        if(show_seconds && seconds > 0) {
            sb.append(seconds).append("秒");
        }

        return sb.toString() ;
    }

    public static String formatUnixTime(Long unix_time){
        if(unix_time==null || unix_time<=0) return "";
        DateFormat format = getDateFormat("yyyy-MM-dd HH:mm:ss");
        return format.format(new Date(unix_time*1000));
    }


    private static final ThreadLocal<Map<String, DateFormat>> dateFormatters = ThreadLocal.withInitial(() -> new HashMap());


    /**
     * 根据格式参数获取当前线程独享的DateFormat
     * @param pattern
     * @return
     */
    public static DateFormat getDateFormat(String pattern) {
        Map<String, DateFormat> formatters = dateFormatters.get();
        DateFormat formatter = formatters.get(pattern);
        if (formatter == null) {
            formatter = new SimpleDateFormat(pattern);
            formatters.put(pattern, formatter);
        }
        return formatter;
    }

    /**
     * 模拟php microtime(true) 函数
     * @return
     */
    public static double microtime(){
        return System.currentTimeMillis()/1000.00;
    }

    /**
     * 查询day天前的时间
     * @return
     */
    public static Long getDaysAgoSecond(int day){
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.DAY_OF_MONTH,-day);
        instance.set(Calendar.HOUR_OF_DAY,0);
        instance.set(Calendar.MINUTE,0);
        instance.set(Calendar.SECOND,0);

        return instance.getTimeInMillis()/1000;
    }


    public static long diffMilliseconds(Date date1, Date date2){
        return (date1!=null?date1.getTime():0L) - (date2!=null?date2.getTime():0L);
    }

    public static long diffSeconds(Date date1, Date date2){
        return ((date1!=null?date1.getTime():0L) - (date2!=null?date2.getTime():0L))/1000L;
    }

    public static long diffMinutes(Date date1, Date date2){
        return ((date1!=null?date1.getTime():0L) - (date2!=null?date2.getTime():0L))/(1000L*60);
    }

    public static long diffHours(Date date1, Date date2){
        return ((date1!=null?date1.getTime():0L) - (date2!=null?date2.getTime():0L))/(1000L*3600);
    }

    /**
     * 计算两个时间戳相差的日期
     * @param t1
     * @param t2
     * @return
     */
    public static int diffDays(Long t1,Long t2){
        return (int)((t1-t2)/(24*3600*1000));
    }

    public static int diffDays(Date d1,Date d2){
        return diffDays(d1.getTime(),d2.getTime());
    }

    /**
     * 判断两个时间戳是否是同一天
     * @param t1
     * @param t2
     * @return
     */
    public static boolean isSameDay(Long t1,Long t2){
        return isSameDay(new Date(t1),new Date(t2));
    }
    public static boolean isSameDay(Date d1,Date d2){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(d1);
        int day1 = calendar.get(Calendar.DAY_OF_YEAR);

        calendar.setTime(d2);
        int day2 = calendar.get(Calendar.DAY_OF_YEAR);

        return day1==day2;
    }

    /**
     * 解析字符串为LocalTime。 24:00解析为23:59
     * @param timeStr
     * @return
     */
    public static LocalTime parseLocalTime(String timeStr){
        if(StrKit.isBlank(timeStr)){
            return null;
        }
        if("24:00".equals(timeStr)) timeStr = "23:59";

        return LocalTime.parse(timeStr);
    }


    /**
     * 判断某个时间是否在指定时间段内
     * @param now
     * @param lightStartTime
     * @param lightEndTime
     * @return   是否
     */
    public static boolean isTimeInRange(LocalTime now, LocalTime lightStartTime, LocalTime lightEndTime){
        if(lightStartTime.compareTo(lightEndTime)<0){
            return now.compareTo(lightStartTime)>0 && now.compareTo(lightEndTime)<0;
        }else{
            return  (now.compareTo(lightStartTime)>0) || now.compareTo(lightEndTime)<0;
        }
    }
}
